#include <stdio.h>
#include "u8g2.h"
#include "u8x8.h"
#include "oled_show.h"
#include "driver/i2c_master.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_err.h"
#include "driver/gpio.h"

#define I2C_PORT -1
#define I2C_MASTER_SCL 40
#define I2C_MASTER_SDA 39
#define content_num    5
static char *TAG = "OLED SHOW";

u8g2_t u8g2;
i2c_master_dev_handle_t dev_handle;

//声明回调函数
static int init_gpio(void);
static int output_gpio(bool state);
static int oled_show_reset(int (*gpio_init)(void),int (*gpio_output)(bool state)); // 硬件复位
//////////

// U8G2所需
static int init_i2c(char addr,int frequency);
static int esp32_i2c_write(uint8_t addr, uint32_t idx, uint8_t *data);
static uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
static uint8_t u8x8_byte_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
//////////

struct oled_i oled_show_interface = 
{
    .start_oled = (oled_start_fn_t)oled_show_start,
    .up_oled = (oled_up_fn_t)oled_show_up,
    .down_oled = (oled_down_fn_t)oled_show_down,
    .stop_oled = (oled_stop_fn_t)oled_show_stop,
    .clear_oled = (oled_clear_fn_t)oled_show_isr, // 中断显示
};

int oled_show_init(struct oled_show *self)
{
    self->interface = &oled_show_interface;
    u8g2_Setup_sh1108_i2c_128x160_f(&u8g2, U8G2_R0, u8x8_byte_i2c, u8x8_gpio_and_delay);  //U8G2_R1调整显示方向
    u8g2_InitDisplay(&u8g2);                                                                  
    oled_show_reset(init_gpio,output_gpio);
    ESP_LOGI(TAG,"oled init success");
    u8g2_ClearBuffer(&u8g2); 
    u8g2_SetPowerSave(&u8g2, 0);
    self->show_state = 0;
    self->contnet = 0;
    return 0;
}

int oled_show_start(struct oled_show *self,show_content_fn_t show_content)
{
    int test = show_content(&u8g2,self->show_state,self->contnet);
    self->show_state = test;
    return 0;
}

int oled_show_stop(struct oled_show *self)
{
    return 0;
}

int oled_show_up(struct oled_show *self)
{
    self->contnet++;
    if (self->contnet >content_num)
    {
        self->contnet=1;
    }
    return 0;
}

int oled_show_down(struct oled_show *self)
{
    self->contnet--;
    if (self->contnet ==0)
    {
        self->contnet=content_num;
    }
    return 0;
}

int oled_show_isr(struct oled_show *self)   //中断显示
{
    self->show_state = 1;
    return 0;
}

/*oled硬件复位*/
static int oled_show_reset(int (*gpio_init)(void),int (*gpio_output)(bool state))
{
    if (gpio_init() == 0)
    {
        gpio_output(0);
        vTaskDelay(20 / portTICK_PERIOD_MS);
        gpio_output(1);
        // printf("reset success\n");
        return 0;                       //成功
    }else{ 
        return 1;                       //失败
    }
}

/*初始化连接res的引脚*/
static int init_gpio()
{
    /*配置输出引脚*/
    gpio_config_t io_conf = {};
    io_conf.intr_type = GPIO_INTR_NEGEDGE;        // 下降沿触发
    io_conf.mode = GPIO_MODE_INPUT;               // 输出模式
    io_conf.pin_bit_mask = (1ull<<3);            // 输出位掩码
    io_conf.pull_down_en = 0;                      // 下拉
    io_conf.pull_up_en = 0;                        // 上拉     
    gpio_config(&io_conf);                         // 配置 GPIO
    return 0;
}

/*复位用的按钮*/
static int output_gpio(bool state)
{
    gpio_set_level(3,state);
    return 0;
}

/*ESP32初始化i2c*/
static int init_i2c(char addr,int frequency)
{   
    /*创建i2c总线*/
    i2c_master_bus_config_t i2c_mst_config_1 = {
    .clk_source = I2C_CLK_SRC_DEFAULT,
    .i2c_port = I2C_PORT,
    .scl_io_num = I2C_MASTER_SCL,
    .sda_io_num = I2C_MASTER_SDA,
    .glitch_ignore_cnt = 7,
    .flags.enable_internal_pullup = true,
    };
    i2c_master_bus_handle_t bus_handle;
    i2c_new_master_bus(&i2c_mst_config_1, &bus_handle);  //安装i2c总线
    /*i2c驱动配置*/
    i2c_device_config_t dev_cfg = {
        .dev_addr_length = I2C_ADDR_BIT_7,
        .device_address = addr,            
        .scl_speed_hz = frequency,
    };
    i2c_master_bus_add_device(bus_handle,&dev_cfg,&dev_handle); // 安装驱动
    return 0;
}

/*ESP32i2C写数据*/
static int esp32_i2c_write(uint8_t addr, uint32_t idx, uint8_t *data)
{
    i2c_master_transmit(dev_handle,data,idx,-1);
    return 0;
}

/*ESP32gpio和延时与u8g2绑定*/
static uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
    switch (msg)
    {
    case U8X8_MSG_GPIO_AND_DELAY_INIT:
        init_i2c(0x3C,400000);                     // 初始化i2c
	    break;
    case U8X8_MSG_DELAY_MILLI:
        vTaskDelay(arg_int);
        break;
    default:
        return 1;
    }
    return 0;
}

/*ESP32i2c操作与u8g2绑定*/
static uint8_t u8x8_byte_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
    static uint8_t buffer[32]; /* u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */
    static uint8_t buf_idx;
    uint8_t *data;
    switch (msg)
    {
    case U8X8_MSG_BYTE_SEND:
        data = (uint8_t *)arg_ptr;
        while (arg_int > 0)
        {
            buffer[buf_idx++] = *data;
            data++;
            arg_int--;
        }
        break;
    case U8X8_MSG_BYTE_INIT:
        /* 自定义代码添加到 Init I2C 子系统 */
        break;
    case U8X8_MSG_BYTE_SET_DC:
        /* ignored for i2c */
        break;
    case U8X8_MSG_BYTE_START_TRANSFER:
        buf_idx = 0;
        break;
    case U8X8_MSG_BYTE_END_TRANSFER:
        esp32_i2c_write(u8x8_GetI2CAddress(u8x8), buf_idx, buffer);
        break;
    default:
        return 1;
    }
    return 0;
}

